#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
#include <cstring>

static const int BUFFERSIZE = 1024;
class Buffer
{
private:
    std::vector<char> _buffer;
    uint64_t _read_index;  // 读偏移
    uint64_t _write_index; // 写偏移

public:
    Buffer() : _read_index(0), _write_index(0) {}
    ~Buffer() = default;
    // 获取数组首地址
    char *Begin() { return &*(_buffer.begin()); }
    // 获取当前读取位置
    char *ReadPoistion() { return Begin() + _read_index; }
    // 获取当前写入位置
    char *WritePoistion() { return Begin() + _write_index; }

    // 获取缓冲区头部可用空间大小
    uint64_t HeadCapacitySize() { return _read_index; }
    // 获取缓冲区末尾可用空间大小
    uint64_t TailCapacitySize() { return _buffer.size() - _read_index; }
    // 获取可读数据大小
    uint64_t ReadAbleSize() { return _write_index - _read_index; }

    // 清空缓冲区
    void clear() { _read_index = _write_index = 0; }

    // 读指针向后移动
    void MoveReadIndex(uint64_t len)
    {
        // 移动的长度为0 or 移动的长度大于可读数据了
        if (len == 0)
            return;
        assert(len <= ReadAbleSize());
        // 移动读偏移
        _read_index += len;
    }
    // 写指针向后移动
    void MoveWriteIndex(uint64_t len)
    {
        // 移动的长度为0 or 移动的长度大于后面剩余空间了
        if(len == 0)  return;
        assert(len <= TailCapacitySize());
        //移动写偏移
        _write_index += len;
    }

    // 确保写入空间足够（数据移动or扩容）
    void EnsureWriteSpace(uint64_t len)
    {
        //后面空间够
        if(TailCapacitySize() >= len) return;
        //移动数据
        if(HeadCapacitySize() + TailCapacitySize() >= len)
        {
            uint64_t size = ReadAbleSize();
            std::copy(ReadPoistion(), ReadPoistion() + size, Begin());
            _read_index = 0;
            _write_index = size;
        }
        //扩容
        else
        {
            _buffer.resize(_write_index + len);
        }
    }

    // 读取数据 + 读偏移移动
    void ReadAndMove(char *data, uint64_t len)
    {
        if(len == 0) return;
        //保证可读的数据大小满足条件
        assert(len <= ReadAbleSize());
        std::copy(ReadPoistion(), ReadPoistion() + len, data);
        MoveReadIndex(len);
    }
    std::string ReadStringAndMove(uint64_t len)
    {
        std::string str;
        ReadAndMove(&str[0], len);
        return str;
    }
    // 写入数据 + 写偏移移动
    void WriteAndMove(const char *data, uint64_t len)
    {
        if(len == 0) return;
        //确保可写位置足够
        EnsureWriteSpace(len);
        std::copy(data, data + len, WritePoistion());
        MoveWriteIndex(len);
    }
    void WriteStringAndMove(const std::string &str)
    {
        WriteAndMove(str.c_str(), str.size());
    }
    void WriteBufferAndMove(Buffer &buf)
    {
        WriteAndMove(buf.ReadPoistion(), buf.ReadAbleSize());
    }

    //获取一行数据
    std::string GetLineAndMove()
    {
        char* pos = (char*)memchr(ReadPoistion(), '\n', ReadAbleSize());
        if(pos == nullptr) return "";
        // 这里的+1是为了把换行符也提取出来
        return ReadStringAndMove(pos - ReadPoistion() + 1);
    }
};

// 使用default就表明编译器只会使用default的成员函数，所以使用default之后，不可以在重载相同的函数了

// copy是模板函数，需要保证前两个参数的类型统一才可以，而且都不能是void*
// template<class InputIterator, class OutputIterator>
//   OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
// {
//   while (first!=last) {
//     *result = *first;
//     ++result; ++first;
//   }
//   return result;
// }